using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using static Unity.Mathematics.math;

// 该 Job 被标记为可进行 "For" 循环并行化的 Job，即每个 Execute 执行一次循环中的一项
// 初始化可视状态
[BurstCompile(FloatPrecision.Standard, FloatMode.Fast)]
struct InitializeVisualizationJob : IJobFor
{
    // 【输出数据】每个格子中所有小块的 3D 位置信息，使用 NativeArray 存储，且允许在并行写入时不受限制
    [WriteOnly, NativeDisableParallelForRestriction]
    public NativeArray<float3> positions;

    // 【输出数据】每个格子中所有小块的 3D 颜色信息，同样为 NativeArray，支持并行写入
    [WriteOnly, NativeDisableParallelForRestriction]
    public NativeArray<float3> colors;

    // 当前可视化网格的总行数（即垂直方向上有多少个格子）
    public int rows;

    // 当前可视化网格的总列数（即水平方向上有多少个格子）
    public int columns;

    // 实现 IJobFor 接口必须的方法：对每一个索引 i 并行执行一次
    // 这里的 i 表示当前正在处理的 “格子” 的索引，从 0 开始，总共有 rows * columns 个格子
    public void Execute (int i)
    {
        // 获取当前格子 i 的中心位置（世界坐标或局部坐标，根据整体系统而定）
        float3 cellPosition = GetCellPosition(i);

        // 每个格子包含多个小块（block），GridVisualization.blocksPerCell 定义了每个格子中小块的数量
        // blockOffset 是当前格子中所有 blocks 在全局 positions 和 colors 数组中的起始索引
        int blockOffset = i * GridVisualization.blocksPerCell;

        // 遍历当前格子中的每一个小块（block）
        for (int bi = 0; bi < GridVisualization.blocksPerCell; bi++)
        {
            // 计算当前小块在其所属格子中的相对位置，并累加到格子的中心位置上，得到该小块的最终世界位置
            positions[blockOffset + bi] = cellPosition + GetBlockPosition(bi);

            // 设置该小块的颜色，此处暂时统一设置为 0.5f（可能是灰度值或占位值，具体含义取决于上层逻辑）
            colors[blockOffset + bi] = 0.5f;
        }
    }

    // 根据小块在其所属格子中的索引 bi，计算该小块相对于格子中心的位置偏移量
    // 本例中，小块似乎以 2D 网格方式排列（行和列），返回的是一个 float3，其中 y 固定为 0（无高度变化）
    float3 GetBlockPosition (int i)
    {
        // 计算当前小块位于格子中的哪一行（r 表示 row，纵向索引）
        int r = i / GridVisualization.columnsPerCell;

        // 计算当前小块位于格子中的哪一列（c 表示 column，横向索引）
        // 总索引 i 减去所在行的起始索引，即得到列偏移
        int c = i - r * GridVisualization.columnsPerCell;

        // 返回该小块的位置偏移：列偏移为 c，行偏移为 r，y 固定为 0
        // 该偏移后续会乘以一个 scale（在 GetCellPosition 中），以得到实际间距
        return float3(c, 0f, r);
    }

    // 根据当前格子的索引 i，计算该格子在整体网格中的中心位置
    // 此函数负责将一维的格子索引 i 转换为二维的行列坐标，并计算出该格子的中心点位置
    float3 GetCellPosition (int i)
    {
        // 计算当前格子位于整体网格中的哪一行（r 表示 row，纵向）
        int r = i / columns;

        // 计算当前格子位于整体网格中的哪一列（c 表示 column，横向）
        // 总索引 i 减去当前行起始索引，即得到列偏移
        int c = i - r * columns;

        // 下面的代码计算的是：该格子在整个网格中的 “中心对齐” 位置
        // 目的是让整个网格在屏幕或空间中居中显示，并考虑六边形/交错布局（见后文）

        // 先计算该格子若按规则网格（无偏移）排列时的原始位置：
        // 列偏移：c 从 0 到 columns-1，减去中间值 (columns - 1) * 0.5f，使得列索引以中心为基准对称分布
        // 行偏移：r 从 0 到 rows-1，减去中间值 (rows - 1) * 0.5f，同理使行索引对称分布
        // 再加上一个额外的 (c & 1) * 0.5f，这是为了实现 “交错排列” 或 “六边形网格” 效果
        //     当列索引 c 为奇数时，(c & 1) == 1，会给 z 轴额外增加 0.5，形成交错感（类似蜂窝状排列）
        // 最后再加上一个常量偏移 0.25f（目的不明确，可能是微调视觉位置）
        return
            float3(
                c - (columns - 1) * 0.5f,         // 列方向居中偏移
                0f,                               // y 方向无偏移
                r - (rows - 1) * 0.5f             // 行方向居中偏移
                - (c & 1) * 0.5f                  // 奇数列时向后偏移 0.5，用于交错布局
                + 0.25f                           // 额外固定偏移，用途可能是视觉微调
            ) * float3(
                GridVisualization.columnsPerCell + 1,  // 列方向上的缩放因子，决定格子之间的水平间距
                0f,                                    // y 方向无缩放
                GridVisualization.rowsPerCell + 1      // 行方向上的缩放因子，决定格子之间的垂直间距
            )
            // 下面这行是对上述位置再做一个偏移校正，目的是让整个网格的几何中心与坐标系原点对齐
            // 减去一个偏移量：(columnsPerCell / 2, 0, rowsPerCell / 2)，以调整整体居中
            - float3(
                GridVisualization.columnsPerCell / 2,  // 列方向整体偏移校正
                0f,                                    // y 方向无校正
                GridVisualization.rowsPerCell / 2      // 行方向整体偏移校正
            );
    }
}